import hashlib
import hmac
from pathlib import Path
from typing import Union, Optional


class HashGenerator:
    """
    安全哈希生成与验证工具

    使用示例:
    >>> hasher = HashGenerator()
    >>> data_hash = hasher.sha256("secret data")
    >>> file_hash = hasher.file_hash("data/sample.csv")
    >>> hasher.verify("data/sample.csv", file_hash)  # True/False
    """

    @staticmethod
    def sha256(data: Union[str, bytes], salt: Optional[bytes] = None) -> str:
        """
        生成数据的SHA-256哈希
        :param data: 要哈希的数据（字符串或字节）
        :param salt: 可选盐值
        :return: 十六进制哈希字符串
        """
        if isinstance(data, str):
            data = data.encode('utf-8')

        sha = hashlib.sha256()
        if salt:
            sha.update(salt)
        sha.update(data)
        return sha.hexdigest()

    @staticmethod
    def file_hash(
            file_path: Union[str, Path],
            algorithm: str = "sha256",
            chunk_size: int = 8192
    ) -> str:
        """
        生成文件的哈希值
        :param file_path: 文件路径
        :param algorithm: 哈希算法（sha256, sha512等）
        :param chunk_size: 读取块大小
        :return: 十六进制哈希字符串
        """
        file_path = Path(file_path)
        if not file_path.exists():
            raise FileNotFoundError(f"文件不存在: {file_path}")

        hash_func = getattr(hashlib, algorithm)()

        with open(file_path, 'rb') as f:
            while chunk := f.read(chunk_size):
                hash_func.update(chunk)

        return hash_func.hexdigest()

    @staticmethod
    def verify(
            data: Union[str, bytes, Path],
            expected_hash: str,
            salt: Optional[bytes] = None
    ) -> bool:
        """
        验证数据是否匹配预期的哈希值
        :param data: 要验证的数据（字符串、字节或文件路径）
        :param expected_hash: 预期的哈希值
        :param salt: 可选盐值
        :return: 如果匹配返回True，否则False
        """
        if isinstance(data, Path) or (isinstance(data, str) and Path(data).exists()):
            actual_hash = HashGenerator.file_hash(data)
        else:
            actual_hash = HashGenerator.sha256(data, salt)

        return hmac.compare_digest(actual_hash, expected_hash)